package com.qfjg.webcore.log;

import com.qfjg.webcore.auth.UserAuth;
import com.qfjg.webcore.common.ExceptionUtils;
import com.qfjg.webcore.common.UserIPUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.*;

@Aspect
@Component
public class ActionAspect {

    @Value("${spring.application.name}")
    public String appname;
    ThreadLocal<logParam> actionInfo = new ThreadLocal<>();
    ThreadLocal<ActionLog> actionlog = new ThreadLocal<>();
    @Pointcut("@annotation(com.qfjg.webcore.log.ActionLog)")
    public void pointCut() {}

    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        logParam logParam=new logParam();
        LogInfo logInfo=new LogInfo();

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();

        ActionLog apiOperation=method.getAnnotation(ActionLog.class);
        actionlog.set(apiOperation);

        logInfo.setTag(apiOperation.tag());

        var ip=UserIPUtils.getIPAddress(request);
        logInfo.setClient_ip(ip);

        if(request.getAttribute("userAuth")!=null){
            UserAuth userAuth = (UserAuth)request.getAttribute("userAuth");
            logInfo.setUid(userAuth.getUid());
        }
        var tokens=(Map<String,String>)request.getAttribute("tokens");

        logInfo.setSession_token(tokens.get("st"));
        logInfo.setPath(request.getServletPath());
        logInfo.setStartTime(new Date());

        logInfo.setClient_token(tokens.get("ct"));

        logParam.setLogInfo(logInfo);
        logParam.setItToken(tokens.get("it"));
        request.setAttribute("actionlog",logInfo);
        actionInfo.set(logParam);
    }


    @AfterReturning(returning = "ret", pointcut = "pointCut()")
    public void doAfterReturning(Object ret) {
        ActionLog alog=actionlog.get();
        actionlog.remove();
        logParam logParam=actionInfo.get();
        actionInfo.remove();
        if(alog.LOG_BEHAVIOR()==ActionLogBehavior.Both
                ||alog.LOG_BEHAVIOR()==ActionLogBehavior.OnlySuccess){
            logParam.getLogInfo().setEndTime(new Date());
            logParam.getLogInfo().setLevel("info");
            LogAgent.saveLog(logParam);
        }
    }

    @AfterThrowing(pointcut="pointCut()",
            throwing="ex")
    public void doAfterThrowing(Throwable ex) {
        ActionLog alog=actionlog.get();
        actionlog.remove();
        logParam logParam=actionInfo.get();
        actionInfo.remove();
        if(alog.LOG_BEHAVIOR()==ActionLogBehavior.Both
                ||alog.LOG_BEHAVIOR()==ActionLogBehavior.OnlyException){
            logParam.getLogInfo().setEndTime(new Date());
            logParam.getLogInfo().setLevel("error");
            logParam.getLogInfo().setException(ExceptionUtils.getException(ex));
            LogAgent.saveLog(logParam);
        }
    }
}
